import json
from datetime import datetime
from django.db import transaction
from decimal import Decimal
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection
from utils.response_code import RETCODE
from .models import *
from apps.goods.models import SKU
from django.http import *
from apps.areas.models import *
from meiduo_mall.settings.dev import LOGGER


class OrderSettlementView(LoginRequiredMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        try:
            addresses = Address.objects.filter(user=request.user, is_deleted=False)
        except Address.DoesNotExist as e:
            LOGGER.error(e)
            addresses = None
        redis_client = get_redis_connection('carts')
        carts_data = redis_client.hgetall(request.user.id)
        # 转换格式
        carts_dict = {}
        for sku_id, carts_data in carts_data.items():
            sku_id = int(sku_id.decode())
            cart_dict = json.loads(carts_data.decode())
            if cart_dict["selected"]:
                carts_dict[sku_id] = cart_dict
        # 计算总数量与总金额
        total_count = 0
        total_amount = Decimal(0.00)
        skus = SKU.objects.filter(id__in=carts_dict.keys())
        for sku in skus:
            # 动态属性添加
            sku.count = carts_dict[sku.id].get('count')
            sku.amount = sku.count * sku.price
            # 计算总数量和总金额
            total_count += sku.count
            total_amount += sku.count * sku.price

            # 运费
        freight = Decimal('10.00')

        # 构造前端数据
        context = {
            'addresses': addresses,
            'skus': skus,
            'total_count': total_count,
            'total_amount': total_amount,
            'freight': freight,
            'payment_amount': total_amount + freight,
            'default_address_id': request.user.default_address_id
        }
        return render(request, 'place_order.html', context)


class OrderCommitView(LoginRequiredMixin, View):
    def post(self, request):
        address_id = json.loads(request.body.decode()).get("address_id")
        pay_method = json.loads(request.body.decode()).get("pay_method")

        # 判空
        if not all([address_id, pay_method]):
            return HttpResponseForbidden('缺少必传参数')
        # 检测地址
        try:
            address = Address.objects.get(id=address_id)
        except Exception as e:
            LOGGER.error(e)
            return HttpResponseForbidden("参数address_id错误")
        # 判断支付方式是否合法
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return HttpResponseForbidden('参数pay_method错误')
        # 生成订单编号
        order_num = datetime.now().strftime('%Y%m%d%H%M%S') + ('%09d' % request.user.id)

        # 开启实务
        with transaction.atomic():
            # 设置回滚点
            save_id = transaction.savepoint()
            try:
                # 保存订单基本信息 OrderInfo（一）
                order = OrderInfo.objects.create(
                    order_id=order_num,
                    user=request.user,
                    address=address,
                    total_count=0,
                    total_amount=Decimal('0'),
                    freight=Decimal('10.00'),
                    pay_method=pay_method,
                    status=OrderInfo.ORDER_STATUS_ENUM['UNPAID'] if pay_method == OrderInfo.PAY_METHODS_ENUM['ALIPAY'] else
                    OrderInfo.ORDER_STATUS_ENUM['UNSEND']
                )
                # 从 redis 中取出商品
                client = get_redis_connection("carts")
                carts_data = client.hgetall(request.user.id)
                carts_dict = {}
                for sku_id, cart_data in carts_data.items():
                    sku_id = int(sku_id.decode())
                    cart_data = json.loads(cart_data.decode())
                    if cart_data["selected"]:
                        carts_dict[sku_id] = cart_data
                # 遍历商品信息
                sku_ids = carts_dict.keys()
                for sku_id in sku_ids:
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        origin_stock = sku.stock
                        origin_sales = sku.sales
                        # 判断库存是否充足
                        sku_count = carts_dict[sku_id]['count']
                        if sku_count > sku.stock:
                            transaction.savepoint_rollback(save_id)
                            return JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                        # 数据逻辑更新
                        new_stock = origin_stock - sku_count
                        new_sales = origin_sales + sku_count
                        result = SKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
                        # 下单失败
                        if result == 0:
                            continue
                        # SPU 增加销量
                        sku.spu.sales += sku_count
                        sku.spu.save()
                        # 保存订单商品信息
                        OrderGoods.objects.create(
                            order=order,
                            sku=sku,
                            count=sku_count,
                            price=sku.price,
                        )
                        # 保存商品订单中总价和总数量
                        order.total_count += sku_count
                        order.total_amount += (sku_count * sku.price)
                        # 下单成功
                        break
                    # 添加邮费和保存订单
                    order.total_amount += order.freight
                    order.save()
            except:
                transaction.savepoint_rollback(save_id)
                return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单失败'})
            # 提交实务
            transaction.savepoint_commit(save_id)
        # 清除购物车已经结算过的商品
        client.hdel(request.user.id, *carts_dict)

        return JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id': order.order_id})


class OrderSuccessView(LoginRequiredMixin, View):
    def get(self, request):
        """订单提交成功展示"""
        order_id = request.GET.get('order_id')
        payment_amount = request.GET.get('payment_amount')
        pay_method = request.GET.get('pay_method')
        context = {
            'order_id': order_id,
            'payment_amount': payment_amount,
            'pay_method': pay_method
        }
        return render(request, "order_success.html", context)

